home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir37 / ms_sh23s.zip / SRC / DIRECTOR.C next >
C/C++ Source or Header  |  1994-08-26  |  11KB  |  574 lines

  1. /*
  2.  * @(#)msd_dir.c 1.4 87/11/06    Public Domain.
  3.  *
  4.  *  A public domain implementation of BSD directory routines for
  5.  *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
  6.  *  August 1897
  7.  *
  8.  *  Modified by Ian Stewartson, Data Logic (istewart@datlog.co.uk).
  9.  *
  10.  *  Updates:  1.  To support OS/2 1.x
  11.  *          2.  To support HPFS long filenames
  12.  *          3.  To support OS/2 2.x
  13.  *          4.  To support TurboC
  14.  *          5.  To support Windows NT
  15.  */
  16.  
  17. #include <sys/types.h>
  18. #include <sys/stat.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21.  
  22. #ifndef __TURBOC__
  23. #  include <malloc.h>
  24. #endif
  25.  
  26. #include <string.h>
  27. #include <limits.h>
  28. #include <ctype.h>
  29. #include <errno.h>
  30. #include <dirent.h>
  31.  
  32. #ifdef __TURBOC__
  33. #  include <dir.h>
  34. #endif
  35.  
  36. #if defined (OS2) || defined (__OS2__)
  37. #  define INCL_DOSFILEMGR
  38. #  define INCL_DOSMISC
  39. #  define INCL_DOSERRORS
  40.  
  41. #  include <os2.h>
  42. #  include <bseerr.h>
  43.  
  44. #  if defined (__OS2__)
  45. #    define DISABLE_HARD_ERRORS    DosError (FERR_DISABLEHARDERR)
  46. #    define ENABLE_HARD_ERRORS    DosError (FERR_ENABLEHARDERR)
  47. #    define FIND_BUFFER        FILEFINDBUF3
  48. #  else
  49. #    define DISABLE_HARD_ERRORS    DosError (HARDERROR_DISABLE)
  50. #    define ENABLE_HARD_ERRORS    DosError (HARDERROR_ENABLE)
  51. #    define FIND_BUFFER        FILEFINDBUF
  52. #  endif
  53.  
  54. #  define ERROR_EMPTY_DIR    ERROR_NO_MORE_FILES
  55.  
  56. #  define FILE_NAME_E        achName
  57. #  define OS_CloseFH(a)        DosFindClose (a)
  58.  
  59. #elif defined (WIN32)
  60. #  include <windows.h>
  61. #  define FILE_NAME_E        cFileName
  62. #  define OS_CloseFH(a)        FindClose (a)
  63. #  define FIND_BUFFER        WIN32_FIND_DATA
  64. #  define DISABLE_HARD_ERRORS    SetErrorMode (0)
  65. #  define ENABLE_HARD_ERRORS    SetErrorMode (SEM_FAILCRITICALERRORS | \
  66.                           SEM_NOOPENFILEERRORBOX);
  67.  
  68. #  define ERROR_EMPTY_DIR    ERROR_FILE_NOT_FOUND
  69.  
  70. #else
  71. #  include <dos.h>
  72. #  define DISABLE_HARD_ERRORS
  73. #  define ENABLE_HARD_ERRORS
  74. #  define OS_CloseFH(a)    
  75.  
  76. #  define ERROR_EMPTY_DIR    18
  77. #define ERROR_NO_MORE_FILES        18
  78.  
  79. #  if defined (__TURBOC__)
  80. #    define FILE_NAME_E        ff_name
  81. #    define FIND_BUFFER        struct ffblk
  82. #  else
  83. #    define FILE_NAME_E        name
  84. #    define FIND_BUFFER        struct find_t
  85. #  endif
  86. #endif
  87.  
  88. #if defined (OS2) || defined (__OS2__)
  89. #  define ATTRIBUTES        (FILE_DIRECTORY | FILE_HIDDEN | FILE_SYSTEM | \
  90.                  FILE_NORMAL | FILE_READONLY | FILE_ARCHIVED)
  91. #elif defined (__TURBOC__)
  92. #  define ATTRIBUTES        (FA_RDONLY | FA_HIDDEN | FA_SYSTEM | \
  93.                  FA_DIREC | FA_ARCH)
  94. #else
  95. #  define ATTRIBUTES        (_A_SUBDIR | _A_HIDDEN | _A_SYSTEM | \
  96.                  _A_NORMAL | _A_RDONLY | _A_ARCH)
  97. #endif
  98.  
  99. /*
  100.  * OS/2 2.x has these missing
  101.  */
  102.  
  103. #ifndef ENOTDIR
  104. #  define ENOTDIR    120    /* Not a directory            */
  105. #endif
  106.  
  107. #ifndef S_IFMT
  108. #  define    S_IFMT    0xf000    /* type of file                */
  109. #endif
  110.  
  111. #ifndef S_ISDIR
  112. #  define S_ISDIR(m)    ((((m) & S_IFMT) == S_IFDIR))
  113. #endif
  114.  
  115. /*
  116.  * Internals
  117.  */
  118.  
  119. typedef struct _dircontents    DIRCONT;
  120. static void            free_dircontents (DIRCONT *);
  121.  
  122. /*
  123.  * Open the directory stream
  124.  */
  125.  
  126. DIR        *opendir (name)
  127. const char    *name;
  128. {
  129.     struct stat        statb;
  130.     DIR            *dirp;
  131.     char        *last;
  132.     DIRCONT        *dp;
  133.     char        *nbuf;
  134.     int            len = strlen (name);
  135.     unsigned long    rc;
  136.     FIND_BUFFER        dtabuf;
  137. #if defined (__OS2__)
  138.     HDIR        d_handle = HDIR_SYSTEM;
  139.     ULONG        d_count = 1;
  140.     bool        HPFS = FALSE;
  141. #elif defined (OS2)
  142.     HDIR        d_handle = HDIR_SYSTEM;
  143.     USHORT        d_count = 1;
  144.     bool        HPFS = FALSE;
  145. #elif defined (WIN32)
  146.     HANDLE        d_handle;
  147.     bool        HPFS = FALSE;
  148. #endif
  149.  
  150.     if (!len)
  151.     {
  152.     errno = ENOTDIR;
  153.     return (DIR *)NULL;
  154.     }
  155.  
  156.     if ((nbuf = malloc (len + 5)) == (char *)NULL)
  157.     return (DIR *) NULL;
  158.  
  159.     strcpy (nbuf, name);
  160.     last = &nbuf[len - 1];
  161.  
  162. /* Ok, DOS is very picky about its directory names.  The following are
  163.  * valid.
  164.  *
  165.  *  c:/
  166.  *  c:.
  167.  *  c:name/name1
  168.  *
  169.  *  c:name/ is not valid
  170.  */
  171.  
  172.     if (((*last == '\\') || (*last == '/')) && (len > 1) &&
  173.     (!((len == 3) && (name[1] == ':'))))
  174.     *(last--) = 0;
  175.  
  176. /* Check its a directory */
  177.  
  178.     DISABLE_HARD_ERRORS;
  179.     rc = stat (nbuf, &statb);
  180.     ENABLE_HARD_ERRORS;
  181.  
  182.     if (rc)
  183.     {
  184.     free (nbuf);
  185.     return (DIR *) NULL;
  186.     }
  187.  
  188.     if (!S_ISDIR (statb.st_mode))
  189.     {
  190.     free (nbuf);
  191.     errno = ENOTDIR;
  192.     return (DIR *)NULL;
  193.     }
  194.  
  195.     if ((dirp = (DIR *) malloc (sizeof (DIR))) == (DIR *) NULL)
  196.     {
  197.     free (nbuf);
  198.     return (DIR *) NULL;
  199.     }
  200.  
  201. /* Set up to find everything */
  202.  
  203.     if ((*last != '\\') && (*last != '/'))
  204.     strcat (last, "/");
  205.  
  206.     strcat (last, "*.*");
  207.  
  208. /* For OS/2, find the file system type */
  209.  
  210. #if defined (OS2) || defined (__OS2__) || defined (WIN32)
  211.     HPFS = IsHPFSFileSystem (nbuf);
  212. #endif
  213.  
  214.     dirp->dd_loc      = 0;
  215.     dirp->dd_cp       = (DIRCONT *) NULL;
  216.     dirp->dd_contents = (DIRCONT *) NULL;
  217.  
  218.     DISABLE_HARD_ERRORS;
  219.  
  220. #if defined (__OS2__)
  221.     rc = DosFindFirst (nbuf, &d_handle, ATTRIBUTES, &dtabuf,
  222.                sizeof (FILEFINDBUF3), &d_count, FIL_STANDARD);
  223. #elif defined (OS2)
  224.     rc = DosFindFirst (nbuf, &d_handle, ATTRIBUTES, &dtabuf,
  225.                sizeof (FILEFINDBUF), &d_count, (ULONG)0);
  226. #elif defined (WIN32)
  227.     d_handle = FindFirstFile (nbuf, &dtabuf);
  228.     rc = (d_handle == INVALID_HANDLE_VALUE) ? GetLastError () : 0;
  229. #elif defined (__TURBOC__)
  230.     rc = findfirst (nbuf, &dtabuf, ATTRIBUTES);
  231. #else
  232.     rc = _dos_findfirst (nbuf, ATTRIBUTES, &dtabuf);
  233. #endif
  234.  
  235.     ENABLE_HARD_ERRORS;
  236.  
  237. /* Check for errors */
  238.  
  239.     if (rc)
  240.     {
  241.     free (nbuf);
  242.  
  243. /* Empty directory */
  244.  
  245. #if defined (ERROR_EMPTY_DIR)
  246.     if (rc == ERROR_EMPTY_DIR)
  247.         return dirp;
  248. #endif
  249.  
  250.     free (dirp);
  251.     return (DIR *) NULL;
  252.     }
  253.  
  254. /* Process the directory */
  255.  
  256.     do
  257.     {
  258.     if (((dp = (DIRCONT *) malloc (sizeof (DIRCONT))) == (DIRCONT *)NULL) ||
  259.         ((dp->_d_entry = strdup (dtabuf.FILE_NAME_E)) == (char *) NULL))
  260.     {
  261.         if (dp->_d_entry != (char *)NULL)
  262.         free ((char *)dp);
  263.  
  264.         free (nbuf);
  265.         free_dircontents (dirp->dd_contents);
  266.  
  267.         OS_CloseFH (d_handle);
  268.         return (DIR *) NULL;
  269.     }
  270.  
  271. #if defined (OS2) || defined (__OS2__) || defined (WIN32)
  272.     if (!HPFS)
  273.         strlwr (dp->_d_entry);
  274. #else
  275.     strlwr (dp->_d_entry);
  276. #endif
  277.  
  278.     if (dirp->dd_contents != (DIRCONT *) NULL)
  279.         dirp->dd_cp = dirp->dd_cp->_d_next = dp;
  280.  
  281.     else
  282.         dirp->dd_contents = dirp->dd_cp = dp;
  283.  
  284.     dp->_d_next = (DIRCONT *) NULL;
  285.  
  286. #if defined (OS2) || defined (__OS2__)
  287.     d_count = 1;
  288.     } while (DosFindNext (d_handle, &dtabuf, sizeof (FILEFINDBUF),
  289.               &d_count) == 0);
  290. #elif defined (WIN32)
  291.     } while (FindNextFile (d_handle, &dtabuf));
  292. #elif defined (__TURBOC__)
  293.     } while (findnext (&dtabuf) == 0);
  294. #else
  295.     } while (_dos_findnext (&dtabuf) == 0);
  296. #endif
  297.  
  298.     dirp->dd_cp = dirp->dd_contents;
  299.     free (nbuf);
  300.  
  301.     OS_CloseFH (d_handle);
  302.     return dirp;
  303. }
  304.  
  305.  
  306. /*
  307.  * Close the directory stream
  308.  */
  309.  
  310. int    closedir (dirp)
  311. DIR    *dirp;
  312. {
  313.     if (dirp != (DIR *)NULL)
  314.     {
  315.     free_dircontents (dirp->dd_contents);
  316.     free ((char *)dirp);
  317.     }
  318.  
  319.     return 0;
  320. }
  321.  
  322. /*
  323.  * Read the next record from the stream
  324.  */
  325.  
  326. struct dirent    *readdir (dirp)
  327. DIR        *dirp;
  328. {
  329.     static struct dirent    dp;
  330.  
  331.     if ((dirp == (DIR *)NULL) || (dirp->dd_cp == (DIRCONT *) NULL))
  332.     return (struct dirent *) NULL;
  333.  
  334.     dp.d_reclen = strlen (strcpy (dp.d_name, dirp->dd_cp->_d_entry));
  335.     dp.d_off    = dirp->dd_loc * 32;
  336.     dp.d_ino    = (ino_t)++dirp->dd_loc;
  337.     dirp->dd_cp = dirp->dd_cp->_d_next;
  338.  
  339.     return &dp;
  340. }
  341.  
  342. /*
  343.  * Restart the directory stream
  344.  */
  345.  
  346. void    rewinddir (dirp)
  347. DIR    *dirp;
  348. {
  349.     seekdir (dirp, (off_t)0);
  350. }
  351.  
  352. /*
  353.  * Move to a know position in the stream
  354.  */
  355.  
  356. void    seekdir (dirp, off)
  357. DIR    *dirp;
  358. off_t    off;
  359. {
  360.     long    i = off;
  361.     DIRCONT    *dp;
  362.  
  363.     if ((dirp == (DIR *)NULL) || (off < 0L))
  364.     return;
  365.  
  366.     for (dp = dirp->dd_contents; (--i >= 0) && (dp != (DIRCONT *)NULL);
  367.      dp = dp->_d_next)
  368.     ;
  369.  
  370.     dirp->dd_loc = off - (i + 1);
  371.     dirp->dd_cp = dp;
  372. }
  373.  
  374. /*
  375.  * Get the current position
  376.  */
  377.  
  378. off_t    telldir(dirp)
  379. DIR    *dirp;
  380. {
  381.     return (dirp == (DIR *)NULL) ? (off_t) -1 : dirp->dd_loc;
  382. }
  383.  
  384. /*
  385.  * Release the internal structure
  386.  */
  387.  
  388. static void    free_dircontents (dp)
  389. DIRCONT        *dp;
  390. {
  391.     DIRCONT    *odp;
  392.  
  393.     while ((odp = dp) != (DIRCONT *)NULL)
  394.     {
  395.     if (dp->_d_entry != (char *)NULL)
  396.         free (dp->_d_entry);
  397.  
  398.     dp = dp->_d_next;
  399.     free ((char *)odp);
  400.     }
  401. }
  402.  
  403. /*
  404.  * For OS/2, we need to know if we have to convert to lower case.  This
  405.  * only applies to non-HPFS (FAT, NETWARE etc) file systems.
  406.  */
  407.  
  408. #if defined (OS2) || defined (__OS2__)
  409.  
  410. /*
  411.  * Define the know FAT systems
  412.  */
  413.  
  414. static char    *FATSystems[] = {"FAT", "NETWARE", (char *)NULL};
  415.  
  416. /*
  417.  * Check for Long filenames
  418.  */
  419.  
  420. bool        IsHPFSFileSystem (char *directory)
  421. {
  422.     ULONG        lMap;
  423.     BYTE        bData[128];
  424.     BYTE        bName[3];
  425.     int            i;
  426.     char        *FName;
  427.     unsigned long    rc;
  428. #if defined (__OS2__)
  429.     ULONG        cbData;
  430.     ULONG        nDrive;
  431.     PFSQBUFFER2        pFSQ = (PFSQBUFFER2)bData;
  432. #else
  433.     USHORT        cbData;
  434.     USHORT        nDrive;
  435. #endif
  436.  
  437. #ifndef __WATCOMC__
  438.     if ( _osmode == DOS_MODE )
  439.     return FALSE;
  440. #endif
  441.  
  442. /*
  443.  * Mike tells me there are IFS calls to determine this, but he carn't
  444.  * remember which.  So we read the partition info and check for HPFS.
  445.  */
  446.  
  447.     if (isalpha (directory[0]) && (directory[1] == ':'))
  448.     nDrive = toupper (directory[0]) - '@';
  449.  
  450.     else
  451.     DosQCurDisk (&nDrive, &lMap);
  452.  
  453. /* Set up the drive name */
  454.  
  455.     bName[0] = (char) (nDrive + '@');
  456.     bName[1] = ':';
  457.     bName[2] = 0;
  458.  
  459.     cbData = sizeof (bData);
  460.  
  461. /* Read the info, if we fail - assume non-HPFS */
  462.  
  463.     DISABLE_HARD_ERRORS;
  464.  
  465. #  ifdef __OS2__
  466.     rc = DosQFSAttach (bName, 0, FSAIL_QUERYNAME, pFSQ, &cbData);
  467. #  else
  468.     rc = DosQFSAttach (bName, 0, FSAIL_QUERYNAME, bData, &cbData, 0L);
  469. #  endif
  470.  
  471.     ENABLE_HARD_ERRORS;
  472.  
  473.     if (rc)
  474.     return FALSE;
  475.  
  476. #  ifdef __OS2__
  477.     FName = pFSQ->szName + pFSQ->cbName + 1;
  478. #  else
  479.     FName = bData + (*((USHORT *) (bData + 2)) + 7);
  480. #  endif
  481.  
  482. #ifdef TEST
  483.     printf ("File System for <%s> = <%s>\n", directory, FName);
  484. #endif
  485.  
  486.     for (i = 0; FATSystems[i] != (char *)NULL; i++)
  487.     {
  488.         if (stricmp (FName, FATSystems[i]) == 0)
  489.         return FALSE;
  490.     }
  491.  
  492.     return TRUE;
  493. }
  494. #endif
  495.  
  496. /*
  497.  * Windows NT version
  498.  */
  499.  
  500. #if defined (WIN32) 
  501. bool        IsHPFSFileSystem (char *directory)
  502. {
  503.     char        bName[4];
  504.     DWORD        flags;
  505.     DWORD        maxname;
  506.     BOOL        rc;
  507.     unsigned int    nDrive;
  508.     char        szCurDir [MAX_PATH];
  509.  
  510.     if (isalpha (directory[0]) && (directory[1] == ':'))
  511.     nDrive = toupper (directory[0]) - '@';
  512.  
  513.     else
  514.     {
  515.     GetCurrentDirectory (MAX_PATH, szCurDir);
  516.     nDrive = szCurDir[0] - 'A' + 1;
  517.     }
  518.  
  519. /* Set up the drive name */
  520.  
  521.     strcpy (bName, "x:\\");
  522.     bName[0] = (char) (nDrive + '@');
  523.  
  524. /* Read the volume info, if we fail - assume non-HPFS */
  525.  
  526.     DISABLE_HARD_ERRORS;
  527.  
  528.     rc = GetVolumeInformation (bName, (LPTSTR)NULL, 0, (LPDWORD)NULL,
  529.                    &maxname, &flags, (LPTSTR)NULL, 0);
  530.     ENABLE_HARD_ERRORS;
  531.  
  532. #ifdef TEST
  533.     printf ("File System flags for <%s> = <0x%.8lx> (%d)\n", directory,
  534.         flags, rc);
  535. #endif
  536.  
  537.     return ((rc) && (flags & (FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED)))
  538.             ? TRUE : FALSE;
  539. }
  540. #endif
  541.  
  542. /*
  543.  * Test program
  544.  */
  545.  
  546. #ifdef TEST
  547. int    main (int argc, char **argv)
  548. {
  549.     int            i;
  550.     struct dirent    *cdp;
  551.     DIR            *dp;
  552.  
  553.     for (i = 1; i < argc; i++)
  554.     {
  555. #if defined (OS2) || defined (__OS2__) || defined (WIN32)
  556.     printf ("IsHPFSFileSystem returns %d\n", IsHPFSFileSystem (argv[1]));
  557. #endif
  558.  
  559.         if ((dp = opendir (argv[i])) == (DIR *)NULL)
  560.         printf ("Cannot open %s\n", argv[1]);
  561.  
  562.     else
  563.     {
  564.         while ((cdp = readdir (dp)) != (struct dirent *)NULL)
  565.         printf ("Found %s\n", cdp->d_name);
  566.  
  567.         closedir (dp);
  568.     }
  569.     }
  570.  
  571.     return 0;
  572. }
  573. #endif
  574.